--- title: "03-Spring Boot 多模块自动装配" created: 2025-12-01 tags: - 项目 aliases: - Spring Boot 多模块自动装配 --- # Spring Boot 多模块自动装配 ## **问题背景** 在微服务架构中,通用代码(如全局异常处理、统一响应封装)放在 `common` 模块,其他服务通过 Maven 依赖引入。 **现象**: - ✅ 正常响应:按预期格式返回 - ❌ 异常响应:返回 Spring Boot 默认错误格式,自定义全局异常处理器未生效 ```json // 期望的错误响应 { "code": 40001, "message": "用户不存在", "data": null, "timestamp": 1764591719827 } // 实际返回(Spring Boot 默认格式) { "timestamp": "2025-12-01T12:19:56.458+00:00", "status": 500, "error": "Internal Server Error", "message": "user not found", "path": "/user/login" } ``` --- ## **根本原因** ### **Spring Boot 默认组件扫描规则** `@SpringBootApplication` 默认只扫描 **启动类所在包及其子包**: ```text com.canvaschain.user ← 启动类所在包(会扫描) ├── controller/ ├── service/ └── UserServiceApplication.java com.canvaschain.common ← 不在扫描范围内! ├── exception/ │ └── GlobalExceptionHandler.java ← 未被加载 └── config/ ``` **结论**:`GlobalExceptionHandler` 没有被 Spring 容器管理,所以不生效。 --- ## **解决方案** ### **方案一:手动 ComponentScan(不推荐)** ```java @SpringBootApplication @ComponentScan(basePackages = {"com.canvaschain.user", "com.canvaschain.common"}) public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } } ``` **缺点**: - 每个服务都需要手动添加 - 容易遗漏,维护成本高 --- ### **方案二:Spring Boot 自动装配(推荐)** #### **1. 创建自动配置类** `common` 模块中创建: ```java package com.canvaschain.common.config; import com.canvaschain.common.exception.GlobalExceptionHandler; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Slf4j @Configuration @Import({ GlobalExceptionHandler.class, // 可以继续添加其他需要自动装配的组件 }) public class CommonAutoConfiguration { @PostConstruct public void init() { log.info("✅ CommonAutoConfiguration 已加载"); } } ``` #### **2. 配置自动装配文件** 根据 Spring Boot 版本选择: **Spring Boot 2.7 及以下** 创建文件:`src/main/resources/META-INF/spring.factories` ```properties org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.canvaschain.common.config.CommonAutoConfiguration ``` **Spring Boot 3.x** 创建文件:`src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` ```text com.canvaschain.common.config.CommonAutoConfiguration ``` ![[image-b14f6488.png]] #### **3. 目录结构** ```text common/ ├── pom.xml └── src/main/ ├── java/com/canvaschain/common/ │ ├── config/ │ │ └── CommonAutoConfiguration.java │ ├── exception/ │ │ ├── BusinessException.java │ │ ├── GlobalExceptionHandler.java │ │ └── ThrowUtils.java │ ├── response/ │ │ ├── BaseResponse.java │ │ ├── ErrorCode.java │ │ └── ResultUtils.java │ └── ... └── resources/ └── META-INF/ ├── spring.factories # Spring Boot 2.x └── spring/ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports # Spring Boot 3.x ``` #### **4. 使用方服务(无需任何额外配置)** ```java @SpringBootApplication @EnableDiscoveryClient public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } } ``` 只需在 `pom.xml` 引入依赖即可自动生效: ```xml com.canvaschain common ${project.version} ``` --- ## **自动装配原理** ```text ┌─────────────────────────────────────────────────────────────┐ │ Spring Boot 启动流程 │ ├─────────────────────────────────────────────────────────────┤ │ 1. @SpringBootApplication 触发自动配置 │ │ ↓ │ │ 2. 扫描所有 jar 包中的 META-INF/spring.factories │ │ 或 META-INF/spring/...AutoConfiguration.imports │ │ ↓ │ │ 3. 加载配置的 AutoConfiguration 类 │ │ ↓ │ │ 4. @Import 导入的组件被注册到 Spring 容器 │ │ ↓ │ │ 5. GlobalExceptionHandler 生效 │ └─────────────────────────────────────────────────────────────┘ ``` --- ## **验证方法** ### **1. 查看启动日志** ```text ✅ CommonAutoConfiguration 已加载 ``` ### **2. 检查 Bean 是否注册** ```java @SpringBootTest class AutoConfigTest { @Autowired private ApplicationContext context; @Test void testGlobalExceptionHandlerLoaded() { boolean exists = context.containsBean("globalExceptionHandler"); assertTrue(exists, "GlobalExceptionHandler 应该被自动装配"); } } ``` ### **3. 测试异常响应** ```bash curl -X POST http://localhost:8080/user/login \ -H "Content-Type: application/json" \ -d '{"username":"notexist","password":"123456"}' ``` 期望返回: ```json { "code": 40004, "message": "用户不存在", "data": null, "timestamp": 1764591719827 } ``` --- ## **方案对比** | **特性** | **手动 ComponentScan** | **自动装配(spring.factories)** | | --- | --- | --- | | 配置方式 | 每个服务手动配置 | 一次配置,自动生效 | | 维护成本 | 高,容易遗漏 | 低,对使用方透明 | | 扩展性 | 差 | 好,类似 Spring Boot Starter | | 推荐度 | ❌ | ✅ | --- ## **常见问题** ### **Q1: 两个配置文件都需要吗?** 不需要,根据 Spring Boot 版本选择一个: - Spring Boot 2.7 及以下:`spring.factories` - Spring Boot 3.x:`AutoConfiguration.imports` - 兼容两个版本:两个文件都配置 ### **Q2: 自动装配不生效怎么排查?** 1. 检查配置文件路径是否正确 2. 检查类的全限定名是否正确 3. 检查 common 模块是否被正确打包(`mvn clean install`) 4. 启动时添加 `--debug` 查看自动配置报告 ```bash java -jar app.jar --debug ``` ### **Q3: 如何有条件地启用自动配置?** ```java @Configuration @ConditionalOnProperty(name = "common.exception.enabled", havingValue = "true", matchIfMissing = true) @Import(GlobalExceptionHandler.class) public class CommonAutoConfiguration { } ``` --- ## **参考资料** - [Spring Boot 官方文档 - Creating Your Own Auto-configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-auto-configuration) - [Spring Boot 2.7 Release Notes - Auto-configuration Changes](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes) --- **项目分区导航**:⬅️ [[02-异常处理最佳实践代码|02-异常处理最佳实践代码]] | 03-Spring Boot 多模块自动装配 | ➡️ [[00-接口文档|00-接口文档]]